<?php

class Twis_Handler extends Twis_Handler_Base
{
    private $_handlers = array();
    private $_router = null;

    public function init()
    {
        if($this->getConfig()->get('env.debug', true)) {
            error_reporting(E_ALL | E_STRICT);
        } else {
            error_reporting(0);
        }
        error_reporting(E_ALL | E_STRICT);
        //set_error_handler(array($this, 'errorHandler'));

        $this->registerHandler('user/login', 'Twis_Handler_Login');
        $this->registerHandler('user/register', 'Twis_Handler_Register');
        $this->registerHandler('user/logout', 'Twis_Handler_Logout');
    }

    public function registerHandler($handlerName, $handlerClass)
    {
        $this->_handlers[$handlerName] = $handlerClass;
    }

    public function startUp()
    {
        $response = $this->getResponse();
        $response->setHeader('X-Powered-By', 'Twis');
        try {
            $result = $this->_dispatch();
            $response->send($result);
        } catch(Exception $e) {
            $data = array();
            $data['code'] = $e->getCode();
            $data['message'] = $e->getMessage();
            $data['trace'] = $e->getTraceAsString();
            try {
                $result = $this->getTemplate()->render('error.html', $data);
                $response->send($result);
            } catch(Exception $e) {
                die($e->getMessage());
            }
        }
    }

    private function _dispatch()
    {
        $request = $this->getRequest();
        $router = $this->getRouter();

        // Dispatch registered handler
        if(isset($this->_handlers[$router])) {
            $handlerName = $this->_handlers[$router];
        } else {
            $handlerName = 'Twis_Handler_Front';
        }
        $handlerClass = new $handlerName();
        $handlerClass->setConfig($this->getConfig());
        $handlerClass->setTemplate($this->getTemplate());
        $handlerClass->setRouter($router);
        return $handlerClass->execute();
    }

    /**
     * Matches a user submitted path with parts defined by a map. Assigns and
     * returns an array of variables on a successful match.
     *
     * Example:  /user/:username = 'Social_Handler_Login'
     *
     * @param string $path Path used to match against this routing map
     * @return string|false An string of assigned values or a false on a mismatch
     */
    public function routing($path)
    {
        // Filter path
        $path = trim($path, '/');
        $routers = $this->getRouters();
        if (empty($routers)) {
            return false;
        }

        $routerNames = array_keys($routers);

        // Empty path
        if($path == '') {
            return false;
        }

        // Finded in routers
        if(in_array($path, $routerNames)) {
            return $routers[$path];
        }

        // Matches path with parts defined by a map.
        $query = array();
        $matchedName = null;
        $pathParts = explode('/', $path);
        foreach($routerNames as $routerName) {
            $routerNameParts = explode('/', trim($routerName, '/'));
            if(count($routerNameParts) != count($pathParts)) {
                continue;
            }
            foreach ($pathParts as $key => $pathPart) {
                if($pathPart == '') {
                    continue;
                } else if(strpos($routerNameParts[$key],':') !== false) {
                    $query[substr($routerNameParts[$key], 1)] = $pathPart;
                } else if($routerNameParts[$key] != $pathPart) {
                    continue(2);
                }
            }
            $matchedName = $routers[$routerName];
        }

        // Not found
        if(!$matchedName) {
            return false;
        }

        // Set request query
        if($query) {
            foreach($query as $queryKey => $queryValue) {
                $this->getRequest()->setQuery($queryKey, $queryValue);
            }
        }

        return $matchedName;
    }

    public function errorHandler($errno, $errstr, $errfile, $errline)
    {
        throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
    }
}
